package fi.lappalainen.geoapp.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Sisältää staattiset funktiot kätköjen lukemiseen tiedostosta ja tiedostoon
 * kirjoittamiseen.
 * @author mika.j.lappalainen@gmail.com
 * @version 1.0
 * @since 1.0
 */
public class GeocacheParser {

    /**
     * Oletusmuodostin
     */
    protected GeocacheParser() {
    }

    /**
     * Jäsentää geokätkön/geokätköjen tiedot GPX-tiedostosta.
     * @param filename tiedosto, josta jäsentäminen tehdään.
     * @return Lista kätköistä, jotka luettiin tiedostosta.
     */
    public static CacheList readCachesFromGPXFile(String filename) {
        CacheList retval = new CacheList();
        GeoCache cache = null;
        WayPoint point = null;
        String waypointName = null;
        FileInputStream fstream = null;
        DataInputStream in = null;
        BufferedReader br = null;
        try {
            //Avataan tiedosto parametrinä tulleen nimen perusteella
            fstream = new FileInputStream(filename);
            // Luodaan DataInputStream tiedoston lukua varten
            in = new DataInputStream(fstream);
            br = new BufferedReader(new InputStreamReader(in));
            String strLine;
            //Luetaan rivi kerrallaan
            while ((strLine = br.readLine()) != null) {
                if (strLine.indexOf(GPXTags.WAYPOINT) != -1) {
                    point = new WayPoint();
                    int start = strLine.indexOf("\"");
                    strLine = strLine.substring(start + 1);
                    int end = strLine.indexOf("\"");
                    point.setLatitude(Double.parseDouble(
                            strLine.substring(0, end)));
                    strLine = strLine.substring(end + 1, strLine.length());
                    start = strLine.indexOf("\"");
                    strLine = strLine.substring(start + 1);
                    end = strLine.indexOf("\"");
                    point.setLongitude(Double.parseDouble(
                            strLine.substring(0, end)));
                }
                if (strLine.indexOf(GPXTags.CACHE) != -1) {
                    cache = new GeoCache();
                    if (point != null) {
                        cache.setPoint(point);
                    }
                    if (waypointName != null) {
                        cache.setId(waypointName);
                    }
                }
                if (strLine.indexOf(GPXTags.NAME) != -1) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    cache.setName(strLine.substring(start + 1, end));
                }
                if (strLine.indexOf(GPXTags.ID) != -1) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    waypointName = strLine.substring(start + 1, end);
                }
                if (strLine.indexOf(GPXTags.TYPE) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    cache.setType(strLine.substring(start + 1, end));
                }
                if (strLine.indexOf(GPXTags.CACHE_END) != -1 && cache != null) {
                    retval.add(cache);
                }
                if (strLine.indexOf(GPXTags.CONTAINER) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    cache.setSize(strLine.substring(start + 1, end));
                }
                if (strLine.indexOf(GPXTags.DIFFICULTY) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    cache.setDifficulty(Double.parseDouble(
                            strLine.substring(start + 1, end)));
                }
                if (strLine.indexOf(GPXTags.TERRAIN) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    cache.setTerrain(Double.parseDouble(
                            strLine.substring(start + 1, end)));
                }
                if (strLine.indexOf(GPXTags.SHORT_DESC) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    if (end < 0) {
                        StringBuffer shortDesc = new StringBuffer(
                                strLine.substring(start + 1, strLine.length()));
                        while ((strLine = br.readLine()) != null
                                & strLine.indexOf(GPXTags.END) < 0) {
                            shortDesc.append(strLine);
                        }
                        shortDesc.append(strLine.substring(0,
                                strLine.indexOf(GPXTags.END)));
                        cache.setShortDescription(shortDesc.toString());
                    } else {
                        cache.setShortDescription(
                                strLine.substring(start + 1, end));
                    }
                }
                if (strLine.indexOf(GPXTags.LONG_DESC) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    if (end < 0) {
                        StringBuffer longDesc = new StringBuffer(
                                strLine.substring(start + 1, strLine.length()));
                        while ((strLine = br.readLine()) != null
                                & strLine.indexOf(GPXTags.END) < 0) {
                            longDesc.append(strLine);
                        }
                        longDesc.append(strLine.substring(0,
                                strLine.indexOf(GPXTags.END)));
                        cache.setDescription(longDesc.toString());
                    } else {
                        cache.setDescription(strLine.substring(start + 1, end));
                    }
                }
                if (strLine.indexOf(GPXTags.HINT) != -1 && cache != null) {
                    int start = strLine.indexOf(GPXTags.START);
                    int end = strLine.indexOf(GPXTags.END);
                    if (end < 0) {
                        StringBuffer longHint = new StringBuffer(
                                strLine.substring(start + 1, strLine.length()));
                        while ((strLine = br.readLine()) != null
                                & strLine.indexOf(GPXTags.END) < 0) {
                            longHint.append(strLine);
                        }
                        longHint.append(strLine.substring(0,
                                strLine.indexOf(GPXTags.END)));
                        cache.setHint(longHint.toString());
                    } else {
                        cache.setHint(strLine.substring(start + 1, end));
                    }
                }
            }
            //suljetaan lukustreami
            in.close();
        } catch (Exception e) {
            retval = null;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                retval = null;
            }
        }
        return retval;
    }

    /**
     * Jäsentää geokätkön/geokätköjen tiedot GPX-tiedostoon.
     * @param caches Lista kätköistä, jotka jäsennetään tiedostoon.
     * @param filename tiedosto, johon jäsentäminen tehdään.
     * @return true, jos kirjoitus onnistui, muuten false.
     */
    public static boolean writeCachesToGPXFile(
            final CacheList caches, final String filename) {
        BufferedWriter bufferedWriter = null;
        try {
            //Muodostetaan BufferedWriter olio
            bufferedWriter = new BufferedWriter(new FileWriter(filename));
            //Kirjoitetaan GPX-tiedoston alku
            bufferedWriter.write(GPXTags.XML_VERSION);
            bufferedWriter.newLine();
            bufferedWriter.write(GPXTags.SCHEMA);
            bufferedWriter.newLine();
            //Kirjoitetaan kätköjen tiedot tiedostoon.
            for (int idx = 0; idx < caches.size(); idx++) {
                GeoCache cache = (GeoCache) caches.elementAt(idx);
                bufferedWriter.write(GPXTags.WAYPOINT);
                bufferedWriter.write(GPXTags.SPACE);
                bufferedWriter.write(GPXTags.LAT);
                bufferedWriter.write(GPXTags.EQUAL);
                bufferedWriter.write(GPXTags.QUOTATION);
                bufferedWriter.write(
                        String.valueOf(cache.getPoint().getLatitude()));
                bufferedWriter.write(GPXTags.QUOTATION);
                bufferedWriter.write(GPXTags.SPACE);
                bufferedWriter.write(GPXTags.LONG);
                bufferedWriter.write(GPXTags.EQUAL);
                bufferedWriter.write(GPXTags.QUOTATION);
                bufferedWriter.write(
                        String.valueOf(cache.getPoint().getLongitude()));
                bufferedWriter.write(GPXTags.QUOTATION);
                bufferedWriter.write(GPXTags.END_TAG);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.ID);
                bufferedWriter.write(cache.getId());
                bufferedWriter.write(GPXTags.ID_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.CACHE);
                bufferedWriter.write(GPXTags.START);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.NAME);
                bufferedWriter.write(cache.getName());
                bufferedWriter.write(GPXTags.NAME_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.TYPE);
                bufferedWriter.write(cache.getType().toString());
                bufferedWriter.write(GPXTags.TYPE_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.CONTAINER);
                bufferedWriter.write(cache.getSize().toString());
                bufferedWriter.write(GPXTags.CONTAINER_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.DIFFICULTY);
                bufferedWriter.write("" + cache.getDifficulty());
                bufferedWriter.write(GPXTags.DIFFICULTY_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.TERRAIN);
                bufferedWriter.write("" + cache.getTerrain());
                bufferedWriter.write(GPXTags.TERRAIN_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.SHORT_DESC);
                bufferedWriter.write(GPXTags.SPACE);
                bufferedWriter.write(GPXTags.HTML_FALSE);
                bufferedWriter.write(GPXTags.START);
                bufferedWriter.write(cache.getShortDescription());
                bufferedWriter.write(GPXTags.SHORT_DESC_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.LONG_DESC);
                bufferedWriter.write(GPXTags.SPACE);
                bufferedWriter.write(GPXTags.HTML_FALSE);
                bufferedWriter.write(GPXTags.START);
                bufferedWriter.write(cache.getLongDescription());
                bufferedWriter.write(GPXTags.LONG_DESC_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.HINT);
                bufferedWriter.write(cache.getHint());
                bufferedWriter.write(GPXTags.HINT_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.CACHE_END);
                bufferedWriter.newLine();
                bufferedWriter.write(GPXTags.WAYPOINT_END);
                bufferedWriter.newLine();
            }
            bufferedWriter.write(GPXTags.GPX_END);

        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            return false;
        } finally {
            //Tyhjennetään puskuri ja suljetaan tiedosto.
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.flush();
                    bufferedWriter.close();
                }
            } catch (IOException e) {
                return false;
            }
        }
        return true;
    }
}
